package session

import (
	"fmt"
	"ktvserver/config"
	"ktvserver/ktvutil"
	//"log"
	"math/rand"
	"sort"
	"strings"
	"time"
)

type DownloadRecord struct {
	Number uint32 // 歌曲编号
	Date   int64  // 下载时刻
}

func (record DownloadRecord) GetDate() string {
	return getHumanDate(record.Date)
}

// 用户会话
type UserSession struct {
	Number int

	token      uint64 // 会话的ID - 随机数
	remoteAddr string // 远程的地址
	loginDate  int64  //登录时间
	userCode   string // 用户注册码
	userMAC    string // 用户的机器MAC
	isFreeCode bool   // 是否为免费注册码
	isLogout   bool   // 是否已经离线
	lastActive int64  // 最后的活动时间

	CatID   byte // 分类的ID
	Padding byte // 附加信息

	Speed   uint16 // 速度
	SynCode uint16 // 同步码, 用作校验

	CreateDate     uint32 // 创建时间
	ExpirationDate uint32 // 过期时间

	// 当前状态
	downloadList  []DownloadRecord // 当前的下载列表
	todayDownload int              // 今天的下载数量

	lastRecvSpeedBytes [3]int64
	indexRecvArray     int
	totalRecvBytes     int64 //

	lastSentSpeedBytes [3]int64 // 上一次的下载速度, 单位为字节
	indexSentArray     int
	totalSentBytes     int64 // 数据量

	lastSpeedDate int64 // 最后更新收发数据量的时刻

	//
	location string // 地址
}

// 获取会话的ID
func (sess *UserSession) GetToken() uint64 {
	return sess.token
}

func (sess *UserSession) GetTokenHex() string {
	return fmt.Sprintf("%016x", sess.token)
}

// 获取IP地址
func (sess *UserSession) GetIPAddress() string {
	return getIPAddress(sess.remoteAddr)
}

// 获取MAC地址
func (sess *UserSession) GetMAC() string {
	return sess.userMAC
}

// 获取网速
func (sess *UserSession) GetSpeed() int {

	// 超过数量后限速
	if sess.IsSpeedLimited() {
		speed := config.GetIntValue("download_limit_speed", 200)
		return speed
	}

	return int(sess.Speed)
}

// 是否速度受限
func (sess *UserSession) IsSpeedLimited() bool {

	enable := config.GetIntValue("download_limit_enable", 0)
	count := config.GetIntValue("download_limit_count", 30)

	if enable > 0 && sess.todayDownload >= count {
		return true
	}

	return false
}

// 是否为免费注册码
func (sess *UserSession) IsFreeCode() bool {
	return sess.isFreeCode
}

// 获取短用户注册码
func (sess *UserSession) GetShortUserCode() string {
	code := sess.userCode
	if len(code) > 10 {
		code = sess.userCode[0:10]
	}
	return code
}

// 获取短用户注册码
func (sess *UserSession) GetUserCode() string {
	return sess.userCode
}

// 是否已经过期
func (sess *UserSession) IsExpried() bool {
	// 免费注册码永远有效
	if sess.isFreeCode {
		return false
	}

	now := time.Now().Unix()
	//fmt.Printf("now=%d, exp=%d, created=%d\n", now, sess.ExpirationDate, sess.CreateDate)
	if now > int64(sess.ExpirationDate) || now < int64(sess.CreateDate) {
		return true
	} else {
		return false
	}

	return false
}

// 获取过期时间
func (sess *UserSession) GetExpirationDate() int64 {
	// 如果是免费注册码，则自动添加一年的时间
	if sess.isFreeCode {
		return time.Now().Unix() + (86400 * 365)
	}

	return int64(sess.ExpirationDate)
}

// 有效期
func (sess *UserSession) ExpirationDateString() string {
	tm := time.Unix(sess.GetExpirationDate(), 0)
	return tm.Format("2006-01-02")
}

// 登录时间
func (sess *UserSession) LoginDateString() string {
	tm := time.Unix(sess.loginDate, 0)
	return tm.Format("01-02 15:04")
}

// 最后的活动时间
func (sess *UserSession) ActiveDateString() string {
	return getHumanDate(sess.lastActive)
}

// 设置为可读的时间
func getHumanDate(sec int64) string {
	tm := time.Unix(sec, 0)
	//return tm.Format("2006-01-02 03:04:05 PM")

	// 格式化时间
	now := time.Now()
	duration := now.Sub(tm)
	if duration.Seconds() < 60 {
		return fmt.Sprintf("刚刚")
	} else if duration.Minutes() < 60 {
		return fmt.Sprintf("%.0f 分钟前", duration.Minutes())
	} else if duration.Hours() < 24 {
		return fmt.Sprintf("%.0f 小时前", duration.Hours())
	}

	//t = t.Add(time.Hour * time.Duration(Config.TimeZoneOffset))
	return tm.Format("01-02 15:04")
}

// 当前下载的歌曲编号
func (sess *UserSession) GetDownloadingSongNum() uint32 {

	if len(sess.downloadList) > 0 {
		index := len(sess.downloadList) - 1
		return sess.downloadList[index].Number
	}

	return 0
}

// 获取下载的数量
func (sess *UserSession) GetDownloadCount() int {
	return len(sess.downloadList)
}

// 获取下载记录
func (sess *UserSession) GetDownloadRecord() []DownloadRecord {
	return sess.downloadList
}

// 获取上次的速度, 返回单位为字节
func (sess *UserSession) GetLastSpeed() int64 {
	// 如果已经3秒钟没有更新速度了，说明已经断开连接了
	if time.Now().Unix() > sess.lastSpeedDate+3 {
		return 0
	}

	// 求最近3秒钟的平均速度
	var latestAll int64
	for i := 0; i < 3; i++ {
		latestAll += sess.lastSentSpeedBytes[i]
	}
	return (latestAll / 3)
}

func (sess *UserSession) SetLastSpeed(recvBytes int64, sentBytes int64) {

	sess.lastRecvSpeedBytes[sess.indexRecvArray%3] = recvBytes
	sess.indexRecvArray++
	sess.totalRecvBytes += recvBytes

	sess.lastSentSpeedBytes[sess.indexSentArray%3] = sentBytes
	sess.indexSentArray++
	sess.totalSentBytes += sentBytes // 统计发送的总流量

	sess.lastSpeedDate = time.Now().Unix()
	sess.UpdateActive()
}

// 刷新最后的活动时间
func (sess *UserSession) UpdateActive() int32 {
	sess.lastActive = time.Now().Unix()
	sess.isLogout = false
	return KTV_SESSION_STATUS_OK
}

// 获取已经发送流量的统计
func (sess *UserSession) GetTotalRecvBytes() int64 {
	return sess.totalRecvBytes
}

// 获取已经发送流量的统计
func (sess *UserSession) GetTotalSentBytes() int64 {
	return sess.totalSentBytes
}

// 获取地区
func (sess *UserSession) GetLocation() string {
	return sess.location
}

// 更新地区
func (sess *UserSession) updateLocation() {
	if len(sess.location) == 0 {
		sess.location = ktvutil.GetLocationEx(getIPAddress(sess.remoteAddr))
	}
}

// 更新地区
func (sess *UserSession) UpdateLocation() {
	go sess.updateLocation()
}

// 会话的状态
const KTV_SESSION_STATUS_OK = 0      // 正常
const KTV_SESSION_STATUS_EXPIRED = 1 // 已经过期
const KTV_SESSION_STATUS_INVALID = 2 // 无效
const KTV_SESSION_STATUS_NEW = 3     //与机器码新绑定的
const KTV_SESSION_STATUS_WAITING = 4 //排队下载

// 会话过期的参数
const KTV_SESSION_TIMEOUT = (1800)                 // 登录一次保持30分钟
const KTV_SESSION_CLEAN_OUTDATE = (3600 * 24 * 15) // 可以查看过去15天的会话

// 会话管理器
type SessionManager struct {
	sessions                   map[uint64]*UserSession
	lastResetTodayDownloadDate int64
}

var sessionManager = &SessionManager{sessions: make(map[uint64]*UserSession)}

// 是否已经列入黑名单
func (sm *SessionManager) IsBlockedCode(userCode string) bool {
	return false
}

// 添加到会话列表
func (sm *SessionManager) addSession(userCode string, userMAC string, remoteAddr string, info *KtvUserInfo) uint64 {

	// 检查是否已经存在相同来源的会话
	sess := sm.findSession(userCode, remoteAddr)
	if sess != nil {
		sess.UpdateActive()
		go sess.updateLocation()
		return sess.GetToken()
	}

	newToken := genNewToken()
	newSession := new(UserSession)
	newSession.loginDate = time.Now().Unix()
	newSession.token = newToken
	newSession.remoteAddr = remoteAddr
	newSession.userCode = userCode
	newSession.userMAC = userMAC
	newSession.isFreeCode = IsFreeCode(userCode)

	newSession.CatID = info.CatID                   // 分类的ID
	newSession.Padding = info.Padding               // 附加信息
	newSession.Speed = info.Speed                   // 速度
	newSession.SynCode = info.SynCode               // 同步码, 用作校验
	newSession.CreateDate = info.CreateDate         // 创建时间
	newSession.ExpirationDate = info.ExpirationDate // 过期时间

	// 用户信息
	newSession.downloadList = []DownloadRecord{} // 下载列表

	// 刷新活动时间
	newSession.UpdateActive()

	// 添加到会话列表
	sm.sessions[newToken] = newSession

	// 获取地区来源
	go newSession.updateLocation()

	return newToken
}

// 用户登录
func (sm *SessionManager) Login(userCode string, userMAC string, remoteAddr string) (result int, token uint64) {

	// 完成函数后刷新状态
	defer sm.Update()

	// 统一为大写
	userCode = strings.ToUpper(userCode)
	userMAC = strings.ToUpper(userMAC)

	// 解密用户注册码, 检查是否被列入黑名单
	userInfo, _, _, err := DecodeUserLicense(userCode)
	if err != nil || sm.IsBlockedCode(userCode) {
		// 解密失败，无效的注册码
		result = KTV_SESSION_STATUS_INVALID
		token = 0
		return
	}

	// 检查是否已经过期
	if IsFreeCode(userCode) != true && userInfo.IsExpired() {
		result = KTV_SESSION_STATUS_EXPIRED
		token = 0
		return
	}

	// 注册码有效，添加到会话列表
	token = sm.addSession(userCode, userMAC, remoteAddr, userInfo)
	result = KTV_SESSION_STATUS_OK

	return
}

// 退出系统
func (sm *SessionManager) Logout(token uint64, remoteAddr string) {
	// 直接删除token
	delete(sm.sessions, token)

	// 完成函数后刷新状态
	defer sm.Update()
}

// 网络心跳信息
func (sm *SessionManager) Heartbeat(token uint64, remoteAddr string) int32 {

	// 完成函数后刷新状态
	defer sm.Update()

	if sess, found := sm.sessions[token]; found {
		return sess.UpdateActive()
	}

	return KTV_SESSION_STATUS_INVALID
}

// 查找会话
func (sm *SessionManager) findSession(userCode string, remoteAddr string) *UserSession {

	// 查找注册码和IP地址相同的session
	for _, s := range sm.sessions {
		if s.userCode == userCode && getIPAddress(s.remoteAddr) == getIPAddress(remoteAddr) {
			return s
		}
	} // end for

	return nil
}

// 查找会话
func (sm *SessionManager) GetSession(token uint64) *UserSession {

	if sess, found := sm.sessions[token]; found {
		return sess
	}

	return nil
}

// 刷新状态
func (sm *SessionManager) Update() {

	// 清理过期的会话
	sm.RemoveOutdateSession()

	// 重置今日下载的数量
	sm.ResetAllTodayDownloadCount()
}

// 清空所有的会话
func (sm *SessionManager) Clear() {

	for token := range sm.sessions {
		delete(sm.sessions, token)
	} // end for

}

// 获取会话的状态
func (sm *SessionManager) GetTokenStatus(token uint64) int {

	if sess, found := sm.sessions[token]; found {
		if sess.IsExpried() {
			return KTV_SESSION_STATUS_EXPIRED
		}

		return KTV_SESSION_STATUS_OK
	}

	return KTV_SESSION_STATUS_INVALID
}

// 是否会话有效
func (sm *SessionManager) IsAllow(token uint64) bool {
	if sm.GetTokenStatus(token) == KTV_SESSION_STATUS_OK {
		return true
	}

	return false
}

// 清空过期的会话
func (sm *SessionManager) RemoveOutdateSession() {

	now := time.Now().Unix()
	for token, sess := range sm.sessions {
		if now >= sess.lastActive+KTV_SESSION_TIMEOUT {
			sess.isLogout = true
		} else {
			sess.isLogout = false
		}

		if now >= sess.lastActive+KTV_SESSION_CLEAN_OUTDATE {
			delete(sm.sessions, token)
		}

	} // end for

}

func (sm *SessionManager) GetAllSessions() []UserSession {

	all := []UserSession{}

	for _, sess := range sm.sessions {
		all = append(all, *sess)
	} // end for

	// 排序
	sort.Sort(SortSessionByActive(all))

	return all
}

// 设置下载速度
func (sm *SessionManager) SetDownloadingSpeed(token uint64, recvBytes int64, sentBytes int64) {
	sess := sm.GetSession(token)
	if sess != nil {
		sess.SetLastSpeed(recvBytes, sentBytes)
	}
}

func (sm *SessionManager) LogDownloadSongNum(token uint64, number uint32) {
	sess := sm.GetSession(token)
	if sess != nil {
		record := DownloadRecord{Number: number, Date: time.Now().Unix()}
		sess.downloadList = append(sess.downloadList, record)
		sess.todayDownload++
		sess.UpdateLocation()
	}
}

// 重置今天统计的下载数量
func (sm *SessionManager) ResetAllTodayDownloadCount() {

	now := time.Now().Unix()
	if now < sm.lastResetTodayDownloadDate+3600*24 {
		return
	}

	sm.lastResetTodayDownloadDate = now

	for _, sess := range sm.sessions {
		sess.todayDownload = 0
	} // end for

}

//////////////////////////////////////////////////////////////////////////////////////////////////
// 地址的样式 192.168.0.188:12345
func getIPAddress(addr string) string {
	pos := strings.Index(addr, ":")
	if pos < 0 {
		return addr
	} else {
		return addr[0:pos]
	}
}

// 产生新的token
func genNewToken() uint64 {

	rand.Seed(time.Now().Unix())
	s1 := uint32(rand.Uint32())

	rand.Seed(time.Now().UnixNano())
	s2 := uint32(rand.Uint32())

	return uint64(s1) | uint64(s2)<<32
}

//////////////////////////////////////////////////////////////////////////////////////////////////

// 登录到系统
func Login(userCode string, userMAC string, remoteAddr string) (result int, token uint64) {
	return sessionManager.Login(userCode, userMAC, remoteAddr)
}

// 退出系统
func Logout(token uint64, remoteAddr string) {
	sessionManager.Logout(token, remoteAddr)
}

// 网络心跳
func Heartbeat(token uint64, remoteAddr string) int32 {
	return sessionManager.Heartbeat(token, remoteAddr)
}

// 获取会话
func GetSession(token uint64) *UserSession {
	return sessionManager.GetSession(token)
}

// 会话是否有效
func IsAllow(token uint64) bool {
	return sessionManager.IsAllow(token)
}

// 获取所有的会话列表
func GetAllSessions() []UserSession {
	return sessionManager.GetAllSessions()
}

// 获取会话列表
func GetSessionsList(offset int, count int) []UserSession {

	mylist := []UserSession{}

	all := sessionManager.GetAllSessions()
	total := len(all)

	for i := 0; i < count; i++ {

		index := i + offset
		if index >= total {
			break
		}

		sess := all[index]
		sess.Number = index + 1

		mylist = append(mylist, sess)
	}

	//for _, sess := range all {
	//	fmt.Printf("sess.Number=%d\n", sess.Number)
	//}

	return mylist
}

// 获取会话的数量
func GetSessionsCount() int {
	return len(sessionManager.GetAllSessions())
}

// 记录下载的速度
func SetDownloadingSpeed(token uint64, recvBytes int64, sentBytes int64) {
	sessionManager.SetDownloadingSpeed(token, recvBytes, sentBytes)
}

// 记录下载的编号列表
func LogDownloadSongNum(token uint64, number uint32) {
	sessionManager.LogDownloadSongNum(token, number)
}

// GetSpeedLimitInfo
// 获取速度限制信息
func GetSpeedLimitInfo(token uint64) (bool, int) {

	sess := GetSession(token)
	if sess == nil {
		return false, 0
	}

	if sess.IsSpeedLimited() == false {
		return false, 0
	}

	//count := config.GetIntValue("download_limit_count", 30)
	speed := config.GetIntValue("download_limit_speed", 100)

	return true, speed

}
